﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace LNUGame.Model
{
    /// <summary>
    /// Allows us to check collisions between various parts of the game.
    /// Contains methods for checking collision between player and world, enemy and open gaps, and between sprites
    /// </summary>
    class CollisionHandler
    {
        /// <summary>
        /// Handles collision between the player and the world.
        /// Works by trying and moving the player to the new position, if this doesn't work, we move the player back to the last position on the
        /// x-axis or y-axis.
        /// </summary>
        /// <param name="a_level">The level we want to try collision with</param>
        /// <param name="a_oldPos">The old position of the player</param>
        /// <param name="a_newPos">The position the player should try and move to</param>
        /// <param name="a_size">The size of the player</param>
        /// <param name="a_velocity">The velocity of the player</param>
        /// <param name="a_refCollideGround">Reference variable that is set to true when the player hits the ground, is false otherwise</param>
        /// <returns>A Vector2 containing the final position after collision</returns>
        internal Vector2 PlayerCollidWithWorld(Level a_level, Vector2 a_oldPos, Vector2 a_newPos, Vector2 a_size, ref Vector2 a_velocity, ref bool a_refCollideGround)
        {
            //Can we move to the position safely?
            if (a_level.IsCollidingAt(a_newPos, a_size))
            {
                //if not try only the X movement, indicates that a collision with ground or roof has occured

                Vector2 xMove = new Vector2(a_newPos.X, a_oldPos.Y);
                
                if (a_velocity.Y > 0 && a_oldPos.Y - (int)a_oldPos.Y > 0.9f)
                {
                    xMove.Y = (int)a_oldPos.Y + 0.99f;
                }

                if (a_level.IsCollidingAt(xMove, a_size) == false)
                {

                    if (a_velocity.Y > 0)
                    {
                        a_refCollideGround = true;
                        a_velocity.Y *= -0.5f;
                    }
                    else
                    {
                        a_velocity.Y *= 0.5f;
                    }

                    a_velocity.X *= 0.5f;   // friction should be time-dependant

                    return xMove;
                }
                else
                {
                    //try Y movement, indicates that a collision with wall has occured
                    Vector2 yMove = new Vector2(a_oldPos.X, a_newPos.Y);
                    if (a_level.IsCollidingAt(yMove, a_size) == false)
                    {
                        a_velocity.X *= 0.5f;
                        return yMove;
                    }

                    if (a_velocity.Y > 0)
                    {
                        a_refCollideGround = true;
                    }
                    a_velocity.X = 0; //no bounce
                    a_velocity.Y = 0; //no bounce

                }
                //remain at the same position
                return a_oldPos;
            }

            return a_newPos;
        }


        /// <summary>
        /// Checks if an enemy is standing over a gap
        /// </summary>
        /// <param name="a_level">The level we want to check</param>
        /// <param name="a_position">The position of the enemy</param>
        /// <returns>True if the enemy is standing over a gap, false otherwise</returns>
        internal bool EnemyIsStandingOverGap(Level a_level, Vector2 a_position)
        {
            if(a_level.IsEnemyStandingOverGap(a_position))
            {
                return true;
            }
            return false;
        }


        /// <summary>
        /// Checks if there is a collision between two sprites
        /// </summary>
        /// <param name="a_sprite1">The first sprite we want to check for collision</param>
        /// <param name="a_sprite2">The first sprite we want to check for collision</param>
        /// <returns>True if there is a collision, false otherwise</returns>
        internal bool CollisionBetweenSprites(Actor a_sprite1, Actor a_sprite2)
        {
            Collider sprite1Collider = new Collider(a_sprite1.Position, (a_sprite1.Size.Y / 2.0f));
            Collider sprite2Collider = new Collider(a_sprite2.Position, (a_sprite2.Size.X / 2.0f));
            if (sprite1Collider.DoCollide(sprite2Collider))
            {
                return true;
            }
            return false;
        }
    }
}